<?php

/**
 * 原型模式（对象的克隆）
 * 
 * 定义：用原型实例指定创建对象的种类，并通过拷贝这些原型创建新的对象。
 * 
 * 类型：创建型模式
 * 
 * 角色：
 *  1，抽象原型类：声明克隆自身的接口。
 *  2，具体原型类：实现一个克隆自身的操作。
 * 
 * 作用：快速创建大量相同或相似对象。
 * 
 * 优点：
 *  1， 运行时刻增加和删除产品。Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。
 *  它比其他创建型模式更为灵活，因为客户可以在运行时刻建立和删除原型。
 *  2，改变值以指定新对象。
 *  3， 改变结构以指定新对象。
 *  4，减少子类的构造。工厂方法模式经常产生一个与产品类层次平行的 Creator类层次。
 *  5，用类动态配置应用。一些运行时刻环境允许你动态将类装载到应用中。在像 C + +这样的语言中，
 *  Prototype模式是利用这种功能的关键。
 * 
 * 缺点：
 *  1，每个类必须配备一个克隆方法。
 * 
 * 其它：浅拷贝和深拷贝。
 */

/**
 * 抽象原型
 */
interface Prototype
{
	public function copy();
}

/**
 * 具体原型
 */
class ConcretePrototypeA implements Prototype
{
	private $_name;
	
	public function __construct($name)
	{
		$this->_name = $name;
	}
	
	public function setName($name)
	{
		$this->_name = $name;
	}
	
	public function getName()
	{
		return $this->_name;
	}
	
	public function copy()
	{
		// 浅克隆
		return clone $this;
		// 深克隆
		//return unserialize(serialize($this));
	}
}

class Client
{
	public static function main()
	{
		echo '值类型克隆。<br/>';
		$obj = new ConcretePrototypeA('obj');
		$obj1 = $obj->copy();
		$obj2 = $obj->copy();
		echo '$obj1 === $obj2' . ($obj1 === $obj2 ? '相同' : '不同');
		
		echo '<br/>引用类型克隆。<br/>';
		$obj = new ConcretePrototypeA(new stdClass());
		$obj1 = $obj->copy();
		$obj2 = $obj->copy();
		echo '$obj1 === $obj2' . ($obj1 === $obj2 ? '相同' : '不同');
		echo '<br/>$obj1->name === $obj2->name' . ($obj1->getName() === $obj2->getName() ? '相同' : '不同');
	}
}

Client::main();